/****************************************************************************\
 * @file     BR_Usart.c
 * @author   张伦玮,傅帅
 * @date     2019/12/24
 * @brief    串口通讯，可选是否使用DMA
 ******************************************************************************
 * @attent   【注意，本库使用动态内存分配，.s文件中堆空间不应低于设置的总缓冲区大小】
 ****************************************************************************/
#include "BR_Usart.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define SEND 0
#define RECV 1
/* 私有变量 */
static BR_Usart_t prvUsartArr[6];  // 串口结构体数组
static USART_TypeDef *prvUsartTable[6] = {USART1, USART2, USART3, UART4, UART5, USART6};  // 1-6串口地址对应表
/* 私有函数声明 */
static void prvUsartInit(uint8_t UsartIndex, uint32_t Bound, uint8_t Prio);
static void prvDMA_Init(uint8_t UsartIndex, uint8_t Type, int8_t Prio);
static int prvUsartDMA_Send(BR_Usart_t *pUsartx, uint8_t *Str, uint32_t len);
static int prvUsartSend(BR_Usart_t *pUsartx, uint8_t *Str, uint32_t Len);

/* -------------------------------------------------- Public ----------------------------------------------- */
/**
 * @brief  不使用DMA的串口初始化
 * @param  UsartNum    : 串口号 [1-6]
           bound       : 波特率
           TxBuffSize  : 发送缓冲区大小
           RxPrio      : 串口中断优先级
           vOnRecv     : 来数据时的回调函数，每次一个字节
 */
void BR_vUsartInit(uint8_t UsartNum, uint32_t bound, uint32_t TxBuffSize, uint8_t RxPrio, void ( *vOnRecv )(uint8_t* pData, uint32_t Len))
{
    uint8_t UsartIndex = UsartNum - 1;
    BR_Usart_t *pUsartx = &prvUsartArr[UsartIndex];
    /* 初始化与串口号无关的Info */
    pUsartx->USARTx = prvUsartTable[UsartIndex];
    pUsartx->pTxBuff = malloc(TxBuffSize);
    pUsartx->TxBuffSize = TxBuffSize;
    pUsartx->UseDMA_Send = 0;
    pUsartx->vOnRecv = vOnRecv;
    /* 与串口号相关的Info和外设初始化 */
    prvUsartInit(UsartIndex, bound, RxPrio);
}

/**
 * @brief  使用DMA的串口初始化
 * @param  UsartNum    : 串口号 [1-6]
           bound       : 波特率
           TxBuffSize  : 发送缓冲区大小
           TxPrio      : DMA中断优先级，若为-1则表示仅使用DMA接收
           RxBuffSize  : 接收缓冲区大小，若为0则表示仅使用DMA发送
           RxPrio      : 串口中断优先级
           vOnRecv     : 来数据时的回调函数，每次串口空闲中断后触发
 */
void BR_vUsartInitWithDMA(uint8_t UsartNum, uint32_t Bound,
                          uint32_t TxBuffSize, int8_t TxPrio,
                          uint32_t RxBuffSize, int8_t RxPrio, void ( *vOnRecv )(uint8_t* pData, uint32_t Len))
{
    uint8_t UsartIndex = UsartNum - 1;
    BR_Usart_t *pUsartx = &prvUsartArr[UsartIndex];
    /* 初始化与串口号无关的Info */
    pUsartx->USARTx = prvUsartTable[UsartIndex];
    pUsartx->pTxBuff = malloc(TxBuffSize);
    pUsartx->TxBuffSize = TxBuffSize;
    pUsartx->pRxBuff = malloc(RxBuffSize);
    pUsartx->RxBuffSize = RxBuffSize;
    pUsartx->DMA_Occupied = 0;
    if(TxPrio != -1) pUsartx->UseDMA_Send = 1;
    pUsartx->vOnRecv = vOnRecv;
    /* 与串口号相关的Info和外设初始化 */
    prvUsartInit(UsartIndex, Bound, RxPrio);
    prvDMA_Init(UsartIndex, SEND, TxPrio);
    if(RxBuffSize != 0) prvDMA_Init(UsartIndex, RECV, -1);
}

/**
 * @brief  用法同Printf
 * @param  UsartNum    : 串口号 [1-6]
 * @retval 0表示成功，1表示上次DMA发送仍未结束
 */
int BR_iPrintf(uint8_t UsartNum, const char *Format, ...)
{
    va_list pA;
    uint32_t Length;
    BR_Usart_t *pUsartx = &prvUsartArr[UsartNum - 1];            // 拿取要配置的结构体

    va_start(pA, Format);
    Length = vsnprintf((char*)pUsartx->pTxBuff, pUsartx->TxBuffSize, (char*)Format, pA);
    va_end(pA);
    if (pUsartx->UseDMA_Send)
        return prvUsartDMA_Send(pUsartx, NULL, Length);
    else
        return prvUsartSend(pUsartx, pUsartx->pTxBuff, Length);
}

/**
 * @brief  发送一定长度数据
 * @param  UsartNum    : 串口号 [1-6]
           pData       : 数据首地址
           Len         : 长度
 * @retval 0表示成功，1表示上次DMA发送仍未结束
 */
int BR_iSend(uint8_t UsartNum, uint8_t *pData, uint32_t Len)
{
    BR_Usart_t *pUsartx = &prvUsartArr[UsartNum - 1];            // 拿取要配置的结构体
    if (pUsartx->UseDMA_Send)
        return prvUsartDMA_Send(pUsartx, pData, Len);
    else
        return prvUsartSend(pUsartx, pData, Len);
}

void vVoidFunc(uint8_t * pData, uint32_t Len){
}

/* -------------------------------------------------- Private ----------------------------------------------- */
static void prvUsartInit(uint8_t UsartIndex, uint32_t Bound, uint8_t Prio)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    USART_TypeDef *USARTx = prvUsartTable[UsartIndex];          // 拿取目标串口

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;                // 复用功能
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;           // 速度50MHz
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;              // 推挽复用输出
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;                // 上拉

    USART_InitStructure.USART_BaudRate = Bound;                 // 波特率设置
    USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 字长为8位数据格式
    USART_InitStructure.USART_StopBits = USART_StopBits_1;      // 一个停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;         // 无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  // 无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;      // 收发模式

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = Prio;// 抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;          // 子优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             // IRQ通道使能

    switch(UsartIndex)
    {
    case 0:             // 串口1
        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
        GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
        GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
        GPIO_Init(GPIOA,&GPIO_InitStructure);
        break;
    case 1:      // 串口2
        NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
        GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);
        GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
        GPIO_Init(GPIOA,&GPIO_InitStructure);
        break;
    case 2:      // 串口3
        NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
        GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3);
        GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART3);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
        GPIO_Init(GPIOB,&GPIO_InitStructure);
        break;
    case 3:      // 串口4
        NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);
        GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_UART4);
        GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_UART4);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
        GPIO_Init(GPIOC,&GPIO_InitStructure);
        break;
    case 4:      // 串口5
        NVIC_InitStructure.NVIC_IRQChannel = UART5_IRQn;
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);
        GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_UART5);
        GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_UART5);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
        GPIO_Init(GPIOC,&GPIO_InitStructure);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
        GPIO_Init(GPIOD,&GPIO_InitStructure);
        break;
    case 5:      // 串口6
        NVIC_InitStructure.NVIC_IRQChannel = USART6_IRQn;
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6, ENABLE);
        GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_USART6);
        GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_USART6);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
        GPIO_Init(GPIOC,&GPIO_InitStructure);
        break;
    }
    //USARTx 初始化
    USART_Init(USARTx, &USART_InitStructure);       // 初始化串口x
    USART_Cmd(USARTx, ENABLE);                      // 使能串口x
    NVIC_Init(&NVIC_InitStructure);                 // 根据指定的参数初始化NVIC寄存器
    USARTx->SR;
    USARTx->DR;
    USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE);  // 开启相关中断
    USART_ITConfig(USARTx, USART_IT_IDLE, DISABLE);
}

static void prvDMA_Init(uint8_t UsartIndex, uint8_t Type, int8_t Prio)
{
    DMA_InitTypeDef DMA_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    BR_Usart_t *pUsartx = &prvUsartArr[UsartIndex];            // 拿取要配置的结构体
    USART_TypeDef *USARTx = prvUsartTable[UsartIndex];         // 拿取要配置的串口号
    DMA_Stream_TypeDef* DMAy_Streamx;                          // 拿取要配置的DMA_Stream

    /* 非公共部分配置 */
    if(Type == SEND)
    {
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = Prio;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)pUsartx->pTxBuff;     // DMA 存储器0地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;                 // 存储器到外设模式DMA_DIR_MemoryToPeripheral
        DMA_InitStructure.DMA_BufferSize = 0;                                   // 数据传输量
        switch(UsartIndex)
        {
        case 0:      // 串口1
            pUsartx->TxDMA_Flag = DMA_FLAG_TCIF7;
            pUsartx->TxDMA_Stream = DMA2_Stream7;
            DMA_InitStructure.DMA_Channel = DMA_Channel_4;                  // 通道选择
            NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream7_IRQn;         // 中断号选择
            break;
        case 1:      // 串口2
            pUsartx->TxDMA_Flag = DMA_FLAG_TCIF6;
            pUsartx->TxDMA_Stream = DMA1_Stream6;
            DMA_InitStructure.DMA_Channel = DMA_Channel_4;
            NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream6_IRQn;
            break;
        case 2:      // 串口3
            pUsartx->TxDMA_Flag = DMA_FLAG_TCIF3;
            pUsartx->TxDMA_Stream = DMA1_Stream3;
            DMA_InitStructure.DMA_Channel = DMA_Channel_4;
            NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream3_IRQn;
            break;
        case 3:      // 串口4
            pUsartx->TxDMA_Flag = DMA_FLAG_TCIF4;
            pUsartx->TxDMA_Stream = DMA1_Stream4;
            DMA_InitStructure.DMA_Channel = DMA_Channel_4;
            NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream4_IRQn;
            break;
        case 4:      // 串口5
            pUsartx->TxDMA_Flag = DMA_FLAG_TCIF7;
            pUsartx->TxDMA_Stream = DMA1_Stream7;
            DMA_InitStructure.DMA_Channel = DMA_Channel_4;
            NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream7_IRQn;
            break;
        case 5:      // 串口6
            pUsartx->TxDMA_Flag = DMA_FLAG_TCIF6;
            pUsartx->TxDMA_Stream = DMA2_Stream6;
            DMA_InitStructure.DMA_Channel = DMA_Channel_5;
            NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream6_IRQn;
            break;
        }
        DMAy_Streamx = pUsartx->TxDMA_Stream;
    }else if(Type == RECV)
    {
        DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)pUsartx->pRxBuff; // DMA 存储器0地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;             // 外设到储存器模式DMA_DIR_PeripheralToMemory
        DMA_InitStructure.DMA_BufferSize = pUsartx->RxBuffSize;             // 数据传输量
        switch(UsartIndex)
        {
        case 0:
            pUsartx->RxDMA_Flag = DMA_FLAG_TCIF5;
            pUsartx->RxDMA_Stream = DMA2_Stream5;
            DMA_InitStructure.DMA_Channel = DMA_Channel_4;
            break;
        case 1:
            pUsartx->RxDMA_Flag = DMA_FLAG_TCIF5;
            pUsartx->RxDMA_Stream = DMA1_Stream5;
            DMA_InitStructure.DMA_Channel = DMA_Channel_4;
            break;
        case 2:
            pUsartx->RxDMA_Flag = DMA_FLAG_TCIF1;
            pUsartx->RxDMA_Stream = DMA1_Stream1;
            DMA_InitStructure.DMA_Channel = DMA_Channel_4;
            break;
        case 3:
            pUsartx->RxDMA_Flag = DMA_FLAG_TCIF2;
            pUsartx->RxDMA_Stream = DMA1_Stream2;
            DMA_InitStructure.DMA_Channel = DMA_Channel_4;
            break;
        case 4:
            pUsartx->RxDMA_Flag = DMA_FLAG_TCIF0;
            pUsartx->RxDMA_Stream = DMA1_Stream0;
            DMA_InitStructure.DMA_Channel = DMA_Channel_4;
            break;
        case 5:
            pUsartx->RxDMA_Flag = DMA_FLAG_TCIF1;
            pUsartx->RxDMA_Stream = DMA2_Stream1;
            DMA_InitStructure.DMA_Channel = DMA_Channel_5;
            break;
        }
        DMAy_Streamx = pUsartx->RxDMA_Stream;
    }
    /* 公共部分配置 */
    if((uint32_t)DMAy_Streamx > (uint32_t)DMA2)                 // 得到当前stream是属于DMA2还是DMA1
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);     // DMA2时钟使能
    else
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);     // DMA1时钟使能
    DMA_DeInit(DMAy_Streamx);
    while (DMA_GetCmdStatus(DMAy_Streamx) != DISABLE) {}        // 等待DMA可配置

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USARTx->DR;           // DMA外设地址
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;            // 外设非增量模式
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                     // 存储器增量模式
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;     // 外设数据长度:8位
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;             // 存储器数据长度:8位
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                               // 使用普通模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;                       // 中等优先级
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;                 // 存储器突发单次传输
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;         // 外设突发单次传输
    /* 初始化 */
    DMA_Init(DMAy_Streamx, &DMA_InitStructure);         // 初始化DMA Stream
    DMA_Cmd(DMAy_Streamx, ENABLE);
    if(Type == SEND)
    {
        NVIC_Init(&NVIC_InitStructure);
        USART_DMACmd(USARTx, USART_DMAReq_Tx, ENABLE);  // 使能串口DMA发送
        DMA_ITConfig(DMAy_Streamx, DMA_IT_TC, ENABLE);
    }else if(Type == RECV)
    {
        USART_DMACmd(USARTx, USART_DMAReq_Rx, ENABLE);  // 使能DMA接收
        DMA_SetCurrDataCounter(DMAy_Streamx, pUsartx->RxBuffSize);  // 数据传输量
        USART_ITConfig(USARTx, USART_IT_RXNE, DISABLE); // 关闭串口中断
        USART_ITConfig(USARTx, USART_IT_IDLE, ENABLE);
    }
}

static int prvUsartSend(BR_Usart_t *pUsartx, uint8_t *pStr, uint32_t Len)
{
    uint32_t i = 0;
    while (i < Len)
    {
        USART_SendData(pUsartx->USARTx, pStr[i]);
        while (USART_GetFlagStatus(pUsartx->USARTx, USART_FLAG_TC) != SET);
        USART_ClearFlag(pUsartx->USARTx, USART_FLAG_TC);
        i++;
    }
    return 0;
}

static int prvUsartDMA_Send(BR_Usart_t *pUsartx, uint8_t *pStr, uint32_t Len)
{
    if (pUsartx->DMA_Occupied) return 1;
    DMA_Cmd(pUsartx->TxDMA_Stream, DISABLE);                            // 关闭DMA传输     
    if(pStr != NULL)memcpy(pUsartx->pTxBuff, pStr, Len);                // 从iPrintf调用时不需要memcpy
    while (DMA_GetCmdStatus(pUsartx->TxDMA_Stream) != DISABLE);         // 确保DMA可以被设置
    DMA_SetCurrDataCounter(pUsartx->TxDMA_Stream, Len);                 // 数据传输量
    DMA_Cmd(pUsartx->TxDMA_Stream, ENABLE);                             // 开启DMA传输       
    pUsartx->DMA_Occupied = 1;   
    return 0;
}

static void prvUsartHandler(BR_Usart_t *pUsartx)                        // 串口中断服务程序
{
    uint8_t Data;
    uint32_t RecvLen;
    USART_TypeDef *USARTx = pUsartx->USARTx;
    DMA_Stream_TypeDef* RX_DMA_Stream = pUsartx->RxDMA_Stream;          // 拿取要配置的DMA_Stream

    if (USART_GetITStatus(USARTx, USART_IT_RXNE) != RESET)              // 接收中断
    {
        Data = USART_ReceiveData(USARTx);                               // 读取接收到的数据
        pUsartx->vOnRecv(&Data, 1);
    }
    else if (USART_GetITStatus(USARTx, USART_IT_ORE_RX) != RESET)       // ORE中断
    {
        USARTx->DR;
        USART_ClearITPendingBit(USARTx, USART_IT_ORE_RX);
    }
    else if (USART_GetITStatus(USARTx, USART_IT_IDLE) != RESET)         // 空闲中断
    {
        USART_ClearITPendingBit(USARTx, USART_IT_IDLE);
        DMA_Cmd(RX_DMA_Stream, DISABLE);                                // 关闭DMA传输
        RecvLen = pUsartx->RxBuffSize - DMA_GetCurrDataCounter(RX_DMA_Stream);
        DMA_ClearFlag(RX_DMA_Stream, pUsartx->RxDMA_Flag);
        USARTx->SR;
        USARTx->DR;
        pUsartx->vOnRecv(pUsartx->pRxBuff, RecvLen);
        while (DMA_GetCmdStatus(RX_DMA_Stream) != DISABLE);             // 确保DMA可以被设置
        DMA_SetCurrDataCounter(RX_DMA_Stream, pUsartx->RxBuffSize);     // 数据传输量
        DMA_Cmd(RX_DMA_Stream, ENABLE);                                 // 开启DMA传输
    }
}

static void prvTxDMA_StreamHandler(BR_Usart_t *pUsartx)
{
    if(DMA_GetFlagStatus(pUsartx->TxDMA_Stream, pUsartx->TxDMA_Flag) == SET)
    {        
        pUsartx->DMA_Occupied = 0;
        DMA_ClearFlag(pUsartx->TxDMA_Stream, pUsartx->TxDMA_Flag);
    }
}
/* -------------------------------------------------- 中断服务函数 ----------------------------------------------- */
// USART1相关中断
void USART1_IRQHandler(void)
{
    prvUsartHandler(&prvUsartArr[0]);
}

void DMA2_Stream7_IRQHandler(void)
{
    prvTxDMA_StreamHandler(&prvUsartArr[0]);
}

// USART2相关中断
void USART2_IRQHandler(void)
{
    prvUsartHandler(&prvUsartArr[1]);
}

void DMA1_Stream6_IRQHandler(void)
{
    prvTxDMA_StreamHandler(&prvUsartArr[1]);
}

// USART3相关中断
void USART3_IRQHandler(void)
{
    prvUsartHandler(&prvUsartArr[2]);
}

void DMA1_Stream3_IRQHandler(void)
{
    prvTxDMA_StreamHandler(&prvUsartArr[2]);
}

// USART4相关中断
void UART4_IRQHandler(void)
{
    prvUsartHandler(&prvUsartArr[3]);
}

void DMA1_Stream4_IRQHandler(void)
{
    prvTxDMA_StreamHandler(&prvUsartArr[3]);
}

// USART5相关中断
void UART5_IRQHandler(void)
{
    prvUsartHandler(&prvUsartArr[4]);
}

void DMA1_Stream7_IRQHandler(void)
{
    prvTxDMA_StreamHandler(&prvUsartArr[4]);
}

// USART6相关中断
void USART6_IRQHandler(void)
{
    prvUsartHandler(&prvUsartArr[5]);
}

void DMA2_Stream6_IRQHandler(void)
{
    prvTxDMA_StreamHandler(&prvUsartArr[5]);
}
